import photoGalleryExercise from '../../examples/photoGalleryExercise'

In this exercise, we'll render a grid of photos from [Picsum Photos](https://picsum.photos) in an infinitely-scrolling `FlatList`.

## The finished app

<Example
  prelude={photoGalleryExercise.prelude}
  panes={[
    {
      type: 'player',
      platform: 'ios',
      width: 260,
    },
  ]}
  height={540}
  files={{
    'App.js': require('../../examples/files/exercises/PhotoGallery').default,
    'components/PhotoGrid.js': require('../../examples/files/exercises/PhotoGrid')
      .default,
    'reducers/photos.js': require('../../examples/files/exercises/photos')
      .default,
    'api/picsum.js': require('../../examples/files/exercises/picsum').default,
  }}
/>

## Project set up

Start by initializing a new project. You can use either approach described in the [Environment](/environment) section. If you're using Expo (recommended for beginners), run:

```bash
expo init PhotoGallery --template blank
```

## Project Structure

In this app, we'll follow the suggested structure from the [Project Structure](/app/project_structure) section, and divide our files into 3 directories:

- `api` - for fetching remote data
- `components` - presentational components
- `reducers` - for managing app data with `useReducer`

The final directory structure will look like this:

<FileTreeDiagram>
  {() => ({
    name: 'PhotoGallery',
    children: [
      {
        name: 'api',
        children: ['picsum.js'],
      },
      {
        name: 'components',
        children: ['PhotoGrid.js'],
      },
      {
        name: 'reducers',
        children: ['photos.js'],
      },
      'App.js',
    ],
  })}
</FileTreeDiagram>

## Walkthrough

Here's a step-by-step walkthrough to build this app.

<Example {...photoGalleryExercise} />

## Possible improvements

If you'd like to continue further with this exercise, here are a few ideas:

- Use the `PixelRatio` API to detect the pixel density of the device (e.g. `3`), and fetch higher resolution images if needed. We should also ensure our `Image`s align with pixels, since otherwise the edges may look blurry or have small lines between them.
- Persist the fetched list of images across app launches with [AsyncStorage](/app/persistence/asyncstorage).
- Use [`react-navigation`](/app/navigation/react_navigation) to add a "details" screen that appears when tapping a photo - the `list` API that we're using already returns some photo metadata that you could display.
- Handle errors more gracefully. Retry failed requests a few times, and also show a separate error component if the first page of photos loads but a subsequent one fails.
- Consider a more sophisticated approach for data fetching to avoid the somewhat complex interactions between `useEffect` and `useCallback`. This will only get more complex as our app grows. Ideally, we could wrap our API calls with React's [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html) feature, e.g. by using https://resthooks.io/.
